﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Windows.Forms;
using SwimmingCompetitions.Properties;

namespace SwimmingCompetitions
{
    class ActiveCompetitionMode : CompetitionMode
    {
        /// <summary>
        /// Contains data for either men or women.
        /// </summary>
        private class ScoresData
        {
            /// <summary>
            /// mode : distance -> time[]
            /// </summary>
            public readonly Dictionary<SwimmingGlobals.Mode, Dictionary<int, TimeSpan?[]>> Data = new Dictionary<SwimmingGlobals.Mode, Dictionary<int, TimeSpan?[]>>();
        }

        private const int SCORES_COUNT = 201;

        /// <summary>
        /// Stores scores data for male and female groups.
        /// </summary>
        private static readonly ScoresData[] _scores = new[] {new ScoresData(), new ScoresData()};

        static ActiveCompetitionMode()
        {
            loadResources();
        }

        /// <summary>
        /// Determines, if scores are available for specified race mode.
        /// </summary>
        public static bool IsModeAvailable(SwimmingGlobals.Participants participants, SwimmingGlobals.Mode mode, int distance)
        {
            var data = _scores[(int) participants].Data;
            return data.ContainsKey(mode) && data[mode].ContainsKey(distance);
        }

        /// <summary>
        /// Loads score records.
        /// </summary>
        private static TimeSpan?[] loadRecords(string data)
        {
            var records = data
                .Split(new[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries)
                .Select(SwimmingGlobals.ConvertToTimeSpan).ToArray();
            Debug.Assert(records.Length == SCORES_COUNT, "Wrong score records count");
            return records;
        }

        private static void loadResources()
        {
            var men = _scores[(int)SwimmingGlobals.Participants.Men];
            men.Data[SwimmingGlobals.Mode.Back] = new Dictionary<int, TimeSpan?[]>();
            men.Data[SwimmingGlobals.Mode.Back][50] = loadRecords(Resources.men_back_50);
            men.Data[SwimmingGlobals.Mode.Back][100] = loadRecords(Resources.men_back_100);
            men.Data[SwimmingGlobals.Mode.Back][200] = loadRecords(Resources.men_back_200);
            men.Data[SwimmingGlobals.Mode.Brasse] = new Dictionary<int, TimeSpan?[]>();
            men.Data[SwimmingGlobals.Mode.Brasse][50] = loadRecords(Resources.men_brasse_50);
            men.Data[SwimmingGlobals.Mode.Brasse][100] = loadRecords(Resources.men_brasse_100);
            men.Data[SwimmingGlobals.Mode.Brasse][200] = loadRecords(Resources.men_brasse_200);
            men.Data[SwimmingGlobals.Mode.Butterfly] = new Dictionary<int, TimeSpan?[]>();
            men.Data[SwimmingGlobals.Mode.Butterfly][50] = loadRecords(Resources.men_butt_50);
            men.Data[SwimmingGlobals.Mode.Butterfly][100] = loadRecords(Resources.men_butt_100);
            men.Data[SwimmingGlobals.Mode.Butterfly][200] = loadRecords(Resources.men_butt_200);
            men.Data[SwimmingGlobals.Mode.Complex] = new Dictionary<int, TimeSpan?[]>();
            men.Data[SwimmingGlobals.Mode.Complex][200] = loadRecords(Resources.men_complex_200);
            men.Data[SwimmingGlobals.Mode.Complex][400] = loadRecords(Resources.men_complex_400);
            //TODO: crawl
            var women = _scores[(int)SwimmingGlobals.Participants.Women];
            women.Data[SwimmingGlobals.Mode.Back] = new Dictionary<int, TimeSpan?[]>();
            women.Data[SwimmingGlobals.Mode.Back][50] = loadRecords(Resources.women_back_50);
            women.Data[SwimmingGlobals.Mode.Back][100] = loadRecords(Resources.women_back_100);
            women.Data[SwimmingGlobals.Mode.Back][200] = loadRecords(Resources.women_back_200);
            women.Data[SwimmingGlobals.Mode.Brasse] = new Dictionary<int, TimeSpan?[]>();
            women.Data[SwimmingGlobals.Mode.Brasse][50] = loadRecords(Resources.women_brasse_50);
            women.Data[SwimmingGlobals.Mode.Brasse][100] = loadRecords(Resources.women_brasse_100);
            women.Data[SwimmingGlobals.Mode.Brasse][200] = loadRecords(Resources.women_brasse_200);
            women.Data[SwimmingGlobals.Mode.Butterfly] = new Dictionary<int, TimeSpan?[]>();
            women.Data[SwimmingGlobals.Mode.Butterfly][50] = loadRecords(Resources.women_butt_50);
            women.Data[SwimmingGlobals.Mode.Butterfly][100] = loadRecords(Resources.women_butt_100);
            women.Data[SwimmingGlobals.Mode.Butterfly][200] = loadRecords(Resources.women_butt_200);
            women.Data[SwimmingGlobals.Mode.Complex] = new Dictionary<int, TimeSpan?[]>();
            women.Data[SwimmingGlobals.Mode.Complex][200] = loadRecords(Resources.women_complex_200);
            women.Data[SwimmingGlobals.Mode.Complex][400] = loadRecords(Resources.women_complex_400);
            //TODO: crawl
        }

        private static int getScore(TimeSpan?[] scores, TimeSpan time)
        {
            for (var i = 0; i < scores.Length; ++i)
            {
                if (scores[i] != null)
                {
                    if (time <= scores[i]) return scores.Length - i - 1;
                }
            }
            return 0;
        }

        public override ColumnState[] GetVisualModel()
        {
            var result = new ColumnState[CompetitionModel.ColumnsCount];
            result[CompetitionModel.ColumnSwim] = ColumnState.ReadOnly;
            result[CompetitionModel.ColumnScore] = ColumnState.ReadOnly;
            result[CompetitionModel.ColumnTime] = ColumnState.Default;
            result[CompetitionModel.ColumnParticipant] = ColumnState.ReadOnly;
            result[CompetitionModel.ColumnDefaultTime] = ColumnState.ReadOnly;
            result[CompetitionModel.ColumnRank] = ColumnState.ReadOnly;
            result[CompetitionModel.ColumnTeam] = ColumnState.ReadOnly;
            result[CompetitionModel.ColumnTrack] = ColumnState.ReadOnly;
            return result;
        }

        public override void ProcessCellChanged(CompetitionModel.RaceData data, DataGridViewCellEventArgs e)
        {
            try
            {
                if (e.ColumnIndex == CompetitionModel.ColumnTime)
                {
                    var time = (TimeSpan)data.Table.Rows[e.RowIndex][CompetitionModel.ColumnTime];
                    var score = getScore(_scores[(int) data.Participants].Data[data.Mode][data.Distance], time);

                    data.Table.Rows[e.RowIndex][CompetitionModel.ColumnScore] = score;
                }
            }
            catch (Exception ex)
            {
                Logger.Instance.Log("Cell data change failure: ", ex);
            }
        }
    }
}
